#include <iostream>
#include <string>
#include <string.h>
#include <unistd.h>
#include <vector>
#include<stdlib.h>
#include <wait.h>
#include<time.h>
#include"task.hpp"

using namespace std;

enum ERROR
{
    Option_error = 1, // 调用该程序时发生选项错误
    Fork_error,       // fork失败
    Pipe_error        //pipe失败
};

void UseReminder(const string &str) // 当使用该进程池传入参数不当的时候
{
    cout << "Correct use: " << str << " process_num(The number of processes you need to create)" << endl;
}

class Channel
{
public:
    Channel(int wfd, int channel_id, const string &name)
        : _wfd(wfd), _channel_id(channel_id), _name(name)
    {}

    ~Channel()
    {}

    void PrintDebug()
    {
        printf("wfd:%d _channel_id:%d name:%s\n", _wfd, _channel_id, _name.c_str());
    }

    const string& name() const 
    {
        return _name;
    }

    const int wfd() const 
    {
        return _wfd;
    }

private:
    int _wfd;
    int _channel_id;
    string _name;
};

class ProcessPool
{
public:
    ProcessPool(int process_num)
        : _process_num(process_num)
    {}

    ~ProcessPool()
    {}

    int CreateChannels()
    {
        for (int i = 0; i < _process_num; i++)
        {
            int fd[2] = {0};
            int ret = pipe(fd); // 创建管道
            if (ret < 0)
            {
                // 说明创建管道失败
                perror("pipe");
                return Pipe_error;
            }
            pid_t id = fork();
            if (fd < 0) // 创建子进程失败
            {
                perror("fork");
                return Fork_error;
            }
            if (id == 0)
            {
                // 当前是子进程
                // 因为子进程要通过管道读取信息，所以子进程要关闭输入端
                close(fd[1]);
                // TODO
                dup2(fd[0],0);//从标准输入里读取任务
                work();
                exit(0);
            }
            // 当前是父进程
            // 因为父进程要通过管道输入信息，所以父进程要关闭读端
            close(fd[0]);
            string name = "channel-" + to_string(i);
            _channels.push_back(Channel(fd[1], id, name));
        }
        return 0;
    }

    const Channel& nextChannel()
    {
        static int next=0;
        Channel& channel=_channels[next++];
        next%=_channels.size();
        return channel;
    }

    void Debug()
    {
        for (auto &c : _channels)
            c.PrintDebug();
    }

private:
    int _process_num;
    vector<Channel> _channels;
};

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        UseReminder(argv[0]);
        return Option_error;
    }
    int num = stoi(argv[1]); // 获取要创建的进程的个数
    ProcessPool *processpool_ptr = new ProcessPool(num);
    processpool_ptr->CreateChannels();
    srand((unsigned int)time(nullptr));
    //processpool_ptr->Debug();
    //控制子进程
    while(true)
    {
        //选择通道
        const Channel& ret=processpool_ptr->nextChannel();
        //选择任务
        int code=getTask();
        //将任务码通过管道传递给子进程
        write(ret.wfd(),&code,sizeof(code));
        cout<<"task_code: "<<code<<" name: "<<ret.name()<<endl;
        sleep(1);
    }
    
    //回收进程池
    delete processpool_ptr;
    // 回收子进程
    return 0;
}